gl renderer: Save some matrix multiplications
authorTimm Bäder <mail@baedert.org>
Sat, 6 Oct 2018 07:23:26 +0000 (09:23 +0200)
committerTimm Bäder <mail@baedert.org>
Thu, 11 Oct 2018 10:27:56 +0000 (12:27 +0200)
We do this for every single node, which is a little costly, especially
since the common case for the modelview matrix these days is a simple
translation. So, check whether the new modelview matrix is only a
translation matrix and if so, don't do a full matrix multiplication per
node.

gsk/gl/gskglrenderer.c
gsk/gl/gskglrenderops.c
gsk/gl/gskglrenderopsprivate.h

index ceaf499d00982f129de176010a6676f6b919549d..5ba5840a5372241d6c8c441a2e82a7f011a469b0 100644 (file)
@@ -2140,10 +2140,9 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
   {
     graphene_rect_t transformed_node_bounds;
 
-    graphene_matrix_transform_bounds (&builder->current_modelview,
-                                      &node->bounds,
-                                      &transformed_node_bounds);
-    graphene_rect_offset (&transformed_node_bounds, builder->dx, builder->dy);
+    ops_transform_bounds_modelview (builder,
+                                    &node->bounds,
+                                    &transformed_node_bounds);
 
     if (!graphene_rect_intersection (&builder->current_clip.bounds,
                                      &transformed_node_bounds, NULL))
index 21223ee1570ec27b081db3151de433fe4e9aeb1a..eba7c8fb47bde339870cf1ab11559b30a9e16f12 100644 (file)
@@ -19,6 +19,61 @@ ops_get_scale (const RenderOpBuilder *builder)
               graphene_matrix_get_y_scale (mv));
 }
 
+static inline gboolean
+matrix_is_only_translation (const graphene_matrix_t *mat)
+{
+  graphene_vec4_t row1;
+  graphene_vec4_t row2;
+  graphene_vec4_t row3;
+  graphene_vec4_t row;
+
+  graphene_vec4_init (&row1, 1, 0, 0, 0);
+  graphene_vec4_init (&row2, 0, 1, 0, 0);
+  graphene_vec4_init (&row3, 0, 0, 1, 0);
+
+  graphene_matrix_get_row (mat, 0, &row);
+  if (!graphene_vec4_equal (&row1, &row))
+    return FALSE;
+
+  graphene_matrix_get_row (mat, 1, &row);
+  if (!graphene_vec4_equal (&row2, &row))
+    return FALSE;
+
+  graphene_matrix_get_row (mat, 2, &row);
+  if (!graphene_vec4_equal (&row3, &row))
+    return FALSE;
+
+  graphene_matrix_get_row (mat, 3, &row);
+  if (graphene_vec4_get_w (&row) != 1)
+    return FALSE;
+
+  return TRUE;
+}
+
+void
+ops_transform_bounds_modelview (const RenderOpBuilder *builder,
+                                const graphene_rect_t *src,
+                                graphene_rect_t       *dst)
+{
+  if (builder->modelview_is_translation)
+    {
+      graphene_vec4_t row4;
+
+      /* TODO: We could do the get_row here only once, when setting the new modelview matrix. */
+      graphene_matrix_get_row (&builder->current_modelview, 3, &row4);
+      *dst = *src;
+      graphene_rect_offset (dst, graphene_vec4_get_x (&row4), graphene_vec4_get_y (&row4));
+    }
+  else
+    {
+      graphene_matrix_transform_bounds (&builder->current_modelview,
+                                        src,
+                                        dst);
+    }
+
+  graphene_rect_offset (dst, builder->dx, builder->dy);
+}
+
 void
 ops_set_program (RenderOpBuilder *builder,
                  const Program   *program)
@@ -156,6 +211,7 @@ ops_set_modelview (RenderOpBuilder         *builder,
 
   prev_mv = builder->current_modelview;
   builder->current_modelview = *modelview;
+  builder->modelview_is_translation = matrix_is_only_translation (modelview);
 
   return prev_mv;
 }
index 917c3fc8de03d92010a931d000835892e43c44fa..c77de348b478d1fc244bbc7b95043275c2d0d925 100644 (file)
@@ -221,7 +221,10 @@ typedef struct
   int current_render_target;
   int current_texture;
   GskRoundedRect current_clip;
+
   graphene_matrix_t current_modelview;
+  guint modelview_is_translation : 1;
+
   graphene_matrix_t current_projection;
   graphene_rect_t current_viewport;
   float current_opacity;
@@ -246,6 +249,10 @@ GskRoundedRect    ops_set_clip           (RenderOpBuilder         *builder,
 graphene_matrix_t ops_set_modelview      (RenderOpBuilder         *builder,
                                           const graphene_matrix_t *modelview);
 
+void              ops_transform_bounds_modelview (const RenderOpBuilder *builder,
+                                                  const graphene_rect_t *src,
+                                                  graphene_rect_t       *dst);
+
 graphene_matrix_t ops_set_projection     (RenderOpBuilder         *builder,
                                           const graphene_matrix_t *projection);